package gioco;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.ListIterator;

import javax.swing.Timer;

import elementi.Elemento;
import elementi.ElementoMobile;
import elementi.Gadget;
import elementi.Temporizzato;
import elementi.giocatori.Giocatore;
import grafica.GraficaProxy;

public class Arena {
	public static final int RAGGIO_COLLISIONI = 30;
	
	private LinkedList<Elemento> elementi;
	private LinkedList<Giocatore> giocatori;
	private LinkedList<Temporizzato> temporizzati;
	private LinkedList<ElementoMobile> elementiMobili;
	private LinkedList<ElementoMobile> rimossiMobili = new LinkedList<ElementoMobile>();
	private LinkedList<Temporizzato> rimossiTemporizzati = new LinkedList<Temporizzato>();
	
	private int altezza, larghezza;
	private static Arena arena = new Arena();
	private GestoreCollisioni gestoreCollisioni;
	
//Timer per temporizzazione del gioco; ad ogni clock controlla le collisioni, muove gli elementi,
//aggiorna le vite e le energie e chiama il refresh della grafica.
	
	private Timer timer=new Timer(40, new ActionListener() {
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			
			rimossiMobili.clear();
			rimossiTemporizzati.clear();
			
			ListIterator<ElementoMobile> itelm= elementiMobili.listIterator();
			while(itelm.hasNext()){
				ElementoMobile eit=itelm.next();
				if (!isRimosso(eit))
					gestoreCollisioni.controllaCollisioni(eit,preparaArrayElementi(eit));
			}
			
			itelm = elementiMobili.listIterator();;
			while(itelm.hasNext()){
				ElementoMobile eit=itelm.next();
				if (!isRimosso(eit))
					eit.muovi();
			}
			
			ListIterator<Giocatore> itg = giocatori.listIterator();
			while(itg.hasNext()){
				Giocatore git = itg.next();
				if (!isRimosso(git))
					git.incrementaEnergia();
			}
			GraficaProxy.getSingleton().update();			
			
			
			ListIterator<Temporizzato> itt = temporizzati.listIterator();
			while(itt.hasNext()){
				Temporizzato tit = itt.next();
				Elemento eit =(Elemento)tit;
				if (!isRimosso(eit))
					tit.tickTemporizzato();
			}
			
			itelm = rimossiMobili.listIterator();
			while(itelm.hasNext()){
				ElementoMobile eit = itelm.next();
				elementiMobili.remove(eit);
				elementi.remove(eit);
			}
			
			itt = rimossiTemporizzati.listIterator();
			while(itt.hasNext()){
				Temporizzato tit = itt.next();
				temporizzati.remove(tit);
			}
		}
	});


	private Arena(){}

	public void inizia(LinkedList<ElementoMobile> elementiMobili,
			LinkedList<Elemento> elementi, int larghezza, int altezza) {
		
		this.elementi= elementi;
		this.elementiMobili = elementiMobili;
		
		initGiocatori();
		initTemporizzati();
		
		this.altezza = altezza;
		this.larghezza = larghezza;
		
		this.gestoreCollisioni = GestoreCollisioni.getSingleton();
		this.gestoreCollisioni.setDimensioniArena(larghezza, altezza);
		
		timer.start();
	}

	private void initTemporizzati() {
		temporizzati = new LinkedList<Temporizzato>();
		ListIterator<Elemento> it = this.elementi.listIterator();
		while (it.hasNext()){
			Elemento eit = it.next();
			if (eit instanceof Temporizzato){
				temporizzati.add((Temporizzato)eit);
			}
		}
	}

	private void initGiocatori() {
		this.giocatori = new LinkedList<Giocatore>();
		for(int i = 0; i<elementiMobili.size();i++){
			if(elementiMobili.get(i) instanceof Giocatore){
				giocatori.add((Giocatore)elementiMobili.get(i));
			}
		}
	}
// Restituisce tutti gli elementi i cui centri stanno in un intorno di raggio RAGGIO_COLLISIONI
//	centrato nel centro dell'elemento mobile. In questo modo il controllo � fatto solo sugli elementi
//	vicini e non su tutti gli elementi.
	
	private LinkedList<Elemento> preparaArrayElementi(ElementoMobile el){
	   	LinkedList <Elemento> collidenti=new LinkedList <Elemento>();
	   	
	   	ListIterator<Elemento> itel=elementi.listIterator();
	   	while(itel.hasNext()){
			double aux1,aux2;
			Elemento eit=itel.next();
			
			if(eit != el){
				if((eit instanceof Gadget)){
					Gadget g = (Gadget)eit;
					if (g.Attiva()){
						aux1=eit.getX()- el.getX();
						aux1=aux1*aux1;
						aux2=eit.getY()- el.getY();
						aux2=aux2*aux2;
			
						if(aux1+aux2 <= RAGGIO_COLLISIONI*RAGGIO_COLLISIONI){
							collidenti.add(eit);
						}
					}
				}else{
					aux1=eit.getX()- el.getX();
					aux1=aux1*aux1;
					aux2=eit.getY()- el.getY();
					aux2=aux2*aux2;
		
					if(aux1+aux2 <= RAGGIO_COLLISIONI*RAGGIO_COLLISIONI && !isRimosso(eit)){
						collidenti.add(eit);
					}
				}
			}
		}

		return collidenti;
	}
	
	public int getAltezza(){
		return altezza;
	}
	
	public int getLarghezza(){
		return larghezza;
	}
	
	public LinkedList<Elemento> getElementi() {
		return elementi;
	}
	public void setElementi(LinkedList<Elemento> elementi) {
		this.elementi = elementi;
	}
	public LinkedList<Giocatore> getGiocatori() {
		return giocatori;
	}
	public void setGiocatori(LinkedList<Giocatore> giocatori) {
		this.giocatori = giocatori;
	}
	/*public LinkedList<Dardo> getDardi() {
		return dardi;
	}
	public void setDardi(LinkedList<Dardo> dardi) {
		this.dardi = dardi;
	}
	public LinkedList<IntelligenzaArtificiale> getIntelligenze() {
		return intelligenze;
	}
	public void setIntelligenze(LinkedList<IntelligenzaArtificiale> intelligenze) {
		this.intelligenze = intelligenze;
	}*/
	
	public static Arena getArena(){	
		return arena;
	}
	
	public void aggiungiElementoMobile(ElementoMobile el){
		this.elementiMobili.add(el);
		this.elementi.add(el);
	}
	
	public void aggiungiElemento(Elemento el){
		this.elementi.add(el);
	}
	
	public void aggiungiTemporizzato (Temporizzato t){
		this.temporizzati.add(t);
	}
	
		
	public ElementoMobile rimuoviElementoMobile(ElementoMobile el){
		rimossiMobili.add(el);
		return el;
	}
	
	public Elemento rimuoviElemento(Elemento el){
		elementi.remove(el);
		return el;
	}
	
	public Temporizzato rimuoviTemporizzato(Temporizzato t){
		rimossiTemporizzati.add(t);
		return t;
	}
	
	public boolean isRimosso(Elemento el){
		return rimossiMobili.contains(el);
	}
		
}

